package com.kexio.enterprise.observability.logging.impl;

import com.kexio.enterprise.integration.common.PageResult;
import com.kexio.enterprise.observability.logging.LogService;
import com.kexio.enterprise.observability.logging.annotation.OperateLog;
import com.kexio.enterprise.observability.logging.domain.OperateLogEntry;
import com.kexio.enterprise.observability.logging.query.LogQueryCriteria;
import com.kexio.enterprise.observability.logging.statistics.LogStatistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * 日志服务默认实现
 * 
 * 提供基于内存的日志存储实现
 * 生产环境建议使用数据库或ES存储
 * 
 * @author Kexio
 * @since 1.0.0
 */
@Service
public class DefaultLogService implements LogService {

    private static final Logger log = LoggerFactory.getLogger(DefaultLogService.class);

    // 内存存储，生产环境应该使用数据库
    private final List<OperateLogEntry> logEntries = new CopyOnWriteArrayList<>();
    private final Map<Long, OperateLogEntry> logMap = new ConcurrentHashMap<>();
    
    // ID生成器
    private volatile long idGenerator = 1;

    @Override
    public void log(OperateLogEntry logEntry) {
        if (logEntry == null) {
            return;
        }
        
        try {
            // 设置ID
            logEntry.setId(generateId());
            
            // 存储日志
            logEntries.add(logEntry);
            logMap.put(logEntry.getId(), logEntry);
            
            log.debug("操作日志已记录: {}.{}", logEntry.getModule(), logEntry.getOperation());
            
        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
    }

    @Override
    @Async
    public void logAsync(OperateLogEntry logEntry) {
        log(logEntry);
    }

    @Override
    public void batchLog(List<OperateLogEntry> logEntries) {
        if (logEntries == null || logEntries.isEmpty()) {
            return;
        }
        
        try {
            for (OperateLogEntry entry : logEntries) {
                entry.setId(generateId());
                this.logEntries.add(entry);
                this.logMap.put(entry.getId(), entry);
            }
            
            log.debug("批量记录操作日志: {} 条", logEntries.size());
            
        } catch (Exception e) {
            log.error("批量记录操作日志失败", e);
        }
    }

    @Override
    public List<OperateLogEntry> queryLogs(LogQueryCriteria criteria) {
        if (criteria == null) {
            return new ArrayList<>(logEntries);
        }
        
        return logEntries.stream()
                .filter(entry -> matchesCriteria(entry, criteria))
                .sorted((e1, e2) -> e2.getCreateTime().compareTo(e1.getCreateTime()))
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<OperateLogEntry> queryLogsWithPage(LogQueryCriteria criteria, int page, int size) {
        List<OperateLogEntry> allResults = queryLogs(criteria);
        
        int totalElements = allResults.size();
        int totalPages = (int) Math.ceil((double) totalElements / size);
        int start = page * size;
        int end = Math.min(start + size, totalElements);
        
        List<OperateLogEntry> pageContent = start < totalElements ? 
                allResults.subList(start, end) : Collections.emptyList();
        
        PageResult<OperateLogEntry> result = new PageResult<>();
        result.setContent(pageContent);
        result.setTotalElements(totalElements);
        result.setTotalPages(totalPages);
        result.setPageNumber(page);
        result.setPageSize(size);
        
        return result;
    }

    @Override
    public OperateLogEntry getLogById(Long logId) {
        return logMap.get(logId);
    }

    @Override
    public int deleteLogs(LocalDateTime beforeTime) {
        if (beforeTime == null) {
            return 0;
        }
        
        List<OperateLogEntry> toRemove = logEntries.stream()
                .filter(entry -> entry.getCreateTime().isBefore(beforeTime))
                .collect(Collectors.toList());
        
        for (OperateLogEntry entry : toRemove) {
            logEntries.remove(entry);
            logMap.remove(entry.getId());
        }
        
        log.info("删除 {} 条历史日志", toRemove.size());
        return toRemove.size();
    }

    @Override
    public int clearAllLogs() {
        int size = logEntries.size();
        logEntries.clear();
        logMap.clear();
        
        log.info("清空所有操作日志: {} 条", size);
        return size;
    }

    @Override
    public LogStatistics getLogStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        List<OperateLogEntry> filteredLogs = logEntries.stream()
                .filter(entry -> {
                    LocalDateTime operateTime = entry.getCreateTime();
                    return (startTime == null || !operateTime.isBefore(startTime)) &&
                           (endTime == null || !operateTime.isAfter(endTime));
                })
                .collect(Collectors.toList());
        
        LogStatistics statistics = new LogStatistics();
        statistics.setTotalLogs(filteredLogs.size());
        
        long successCount = filteredLogs.stream()
                .mapToLong(entry -> Boolean.TRUE.equals(entry.getSuccess()) ? 1 : 0)
                .sum();
        statistics.setSuccessLogs(successCount);
        statistics.setFailureLogs(filteredLogs.size() - successCount);
        
        // 模块统计
        Map<String, Long> moduleStats = filteredLogs.stream()
                .collect(Collectors.groupingBy(
                    OperateLogEntry::getModule,
                    Collectors.counting()
                ));
        statistics.setModuleStats(moduleStats);
        
        // 操作统计
        Map<String, Long> operationStats = filteredLogs.stream()
                .collect(Collectors.groupingBy(
                    OperateLogEntry::getOperation,
                    Collectors.counting()
                ));
        statistics.setOperationStats(operationStats);
        
        // 类型统计
        Map<OperateLog.OperationType, Long> typeStats = filteredLogs.stream()
                .collect(Collectors.groupingBy(
                    OperateLogEntry::getType,
                    Collectors.counting()
                ));
        statistics.setTypeStats(typeStats);
        
        // 用户统计
        Map<String, Long> userStats = filteredLogs.stream()
                .filter(entry -> entry.getUsername() != null)
                .collect(Collectors.groupingBy(
                    OperateLogEntry::getUsername,
                    Collectors.counting()
                ));
        statistics.setUserStats(userStats);
        
        // 平均执行时间
        double avgExecutionTime = filteredLogs.stream()
                .filter(entry -> entry.getExecutionTime() != null)
                .mapToLong(OperateLogEntry::getExecutionTime)
                .average()
                .orElse(0.0);
        statistics.setAvgExecutionTime(avgExecutionTime);
        
        return statistics;
    }

    @Override
    public String exportLogs(LogQueryCriteria criteria, String format) {
        // TODO: 实现日志导出功能
        List<OperateLogEntry> logs = queryLogs(criteria);
        
        String filename = "operate_logs_" + System.currentTimeMillis();
        
        switch (format.toLowerCase()) {
            case "csv":
                filename += ".csv";
                // TODO: 实现CSV导出
                break;
            case "excel":
                filename += ".xlsx";
                // TODO: 实现Excel导出
                break;
            case "json":
                filename += ".json";
                // TODO: 实现JSON导出
                break;
            default:
                throw new IllegalArgumentException("不支持的导出格式: " + format);
        }
        
        log.info("导出操作日志: {} 条记录, 格式: {}, 文件: {}", logs.size(), format, filename);
        
        // 返回文件路径（这里简化处理）
        return "/tmp/exports/" + filename;
    }

    /**
     * 检查日志条目是否匹配查询条件
     */
    private boolean matchesCriteria(OperateLogEntry entry, LogQueryCriteria criteria) {
        // 模块匹配
        if (criteria.getModule() != null && !criteria.getModule().equals(entry.getModule())) {
            return false;
        }
        
        // 操作匹配
        if (criteria.getOperation() != null && !criteria.getOperation().equals(entry.getOperation())) {
            return false;
        }
        
        // 类型匹配
        if (criteria.getType() != null && !criteria.getType().equals(entry.getType())) {
            return false;
        }
        
        // 级别匹配
        if (criteria.getLevel() != null && !criteria.getLevel().equals(entry.getLevel())) {
            return false;
        }
        
        // 用户ID匹配
        if (criteria.getUserId() != null && !criteria.getUserId().equals(entry.getUserId())) {
            return false;
        }
        
        // 用户名匹配
        if (criteria.getUsername() != null && !criteria.getUsername().equals(entry.getUsername())) {
            return false;
        }
        
        // 租户ID匹配
        if (criteria.getTenantId() != null && !criteria.getTenantId().equals(entry.getTenantId())) {
            return false;
        }
        
        // 业务键匹配
        if (criteria.getBusinessKey() != null && !criteria.getBusinessKey().equals(entry.getBusinessKey())) {
            return false;
        }
        
        // 成功状态匹配
        if (criteria.getSuccess() != null && !criteria.getSuccess().equals(entry.getSuccess())) {
            return false;
        }
        
        // 追踪ID匹配
        if (criteria.getTraceId() != null && !criteria.getTraceId().equals(entry.getTraceId())) {
            return false;
        }
        
        // 时间范围匹配
        LocalDateTime operateTime = entry.getCreateTime();
        if (criteria.getStartTime() != null && operateTime.isBefore(criteria.getStartTime())) {
            return false;
        }
        if (criteria.getEndTime() != null && operateTime.isAfter(criteria.getEndTime())) {
            return false;
        }
        
        // 标签匹配
        if (criteria.getTags() != null && criteria.getTags().length > 0) {
            String[] entryTags = entry.getTags();
            if (entryTags == null || entryTags.length == 0) {
                return false;
            }
            
            Set<String> entryTagSet = Set.of(entryTags);
            for (String tag : criteria.getTags()) {
                if (!entryTagSet.contains(tag)) {
                    return false;
                }
            }
        }
        
        return true;
    }

    /**
     * 生成ID
     */
    private synchronized long generateId() {
        return idGenerator++;
    }
}
